package com.rogerfan.easy.web.config;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.Filter;

import org.apache.shiro.authc.AuthenticationListener;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.rogerfan.easy.shiro.ChainDefinitionSectionMetaSource;
import com.rogerfan.easy.shiro.RedisShiroSessionDao;
import com.rogerfan.easy.shiro.ShiroDbRealm;
import com.rogerfan.easy.shiro.ShiroRedisCacheManager;
import com.rogerfan.easy.shiro.TokenLoginListener;
import com.rogerfan.easy.shiro.TokenWebSessionManager;
import com.rogerfan.easy.shiro.filter.AppAuthenticationFilter;
import com.rogerfan.easy.shiro.filter.AppPermissionAuthorizationFilter;
import com.rogerfan.easy.shiro.filter.AppUserFilter;

@Configuration
public class ShiroConfig {
	public static final String HASH_ALGORITHM = "MD5";
	public static final int HASH_INTERATIONS = 1;

	@Bean(name = "shiroCookie")
	public SimpleCookie shiroCookie() {
		SimpleCookie sc = new SimpleCookie("SHIROJSID");
		sc.setPath("/");
		return sc;

	}

	@Bean(name = "sessionManager")
	public SessionManager sessionManager(RedisShiroSessionDao shiroSessionDao,
			SimpleCookie shiroCookie) {
		DefaultWebSessionManager sessionManager = new TokenWebSessionManager();
		sessionManager.setSessionIdUrlRewritingEnabled(false);
		sessionManager.setGlobalSessionTimeout(60 * 60 * 1000);
		sessionManager.setSessionValidationSchedulerEnabled(false);
		sessionManager.setSessionDAO(shiroSessionDao);
		sessionManager.setSessionIdCookie(shiroCookie);
		return sessionManager;
	}

	@Bean("shiroFilter")
	public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager,
			ChainDefinitionSectionMetaSource metasource,
			AppAuthenticationFilter authFilter, AppUserFilter userFilter,AppPermissionAuthorizationFilter permFilter) {
		ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
		shiroFilter.setSecurityManager(securityManager);
		shiroFilter.setLoginUrl("/user/login");
		shiroFilter.setUnauthorizedUrl("/");

		Map<String, String> filterMap = new LinkedHashMap<>();
		filterMap.put("/public/**", "anon");
		filterMap.put("/webjars/**", "anon");
		filterMap.put("/api/**", "anon");

		// swagger配置
		filterMap.put("/swagger**", "anon");
		filterMap.put("/v2/api-docs", "anon");
		filterMap.put("/swagger-resources/configuration/ui", "anon");

		filterMap.put("/login.html", "anon");
		filterMap.put("/sys/login", "anon");
		filterMap.put("/captcha.jpg", "anon");
		filterMap.put("/user/login", "authc");
		filterMap.putAll(metasource.getMetaSouce());
		shiroFilter.setFilterChainDefinitionMap(filterMap);
		Map<String, Filter> filters = Maps.newHashMap();
		filters.put("authc", authFilter);
		filters.put("user", userFilter);
		filters.put("perms", permFilter);
		shiroFilter.setFilters(filters);
		return shiroFilter;
	}

	@Bean(name = "userRealm")
	public Realm userRealm(ShiroRedisCacheManager cacheManager) {
		ShiroDbRealm realm = new ShiroDbRealm();
		HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(
				HASH_ALGORITHM);
		matcher.setHashIterations(HASH_INTERATIONS);

		realm.setCredentialsMatcher(matcher);
		realm.setCacheManager(cacheManager);
		return realm;
	}

	@Bean(name = "securityManager")
	public SecurityManager securityManager(Realm userRealm,
			SessionManager sessionManager, AuthenticationListener tokenListener) {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(userRealm);
		securityManager.setSessionManager(sessionManager);
		ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();

		authenticator.setAuthenticationListeners(Lists
				.newArrayList(tokenListener));
		authenticator.setRealms(Lists.newArrayList(userRealm));
		securityManager.setAuthenticator(authenticator);
		return securityManager;
	}

	@Bean(name = "lifecycleBeanPostProcessor")
	public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
		return new LifecycleBeanPostProcessor();
	}

}
